package com.zhiwei.tool;

import com.itextpdf.barcodes.BarcodeQRCode;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.color.Color;
import com.itextpdf.kernel.color.DeviceCmyk;
import com.itextpdf.kernel.color.DeviceRgb;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.*;
import com.itextpdf.layout.element.Image;
import com.zhiwei.pojo.*;
import lombok.Data;
import lombok.experimental.Accessors;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

public class TipGener {
    public static String File_Path;

    public static DecimalFormat PriceFormat = new DecimalFormat("###0.00");

    public static File getInvoice(String filePath, Order order, Bill bill, Products product,
                                  Trader trader, Trader ourCompany, User sealer,
                                  User dealer) throws Exception {
        File_Path = filePath;
        PdfWriter pdfWriter = new PdfWriter(File_Path + "tip.pdf");
        PdfDocument pdfDocument = new PdfDocument(pdfWriter);
//        PageSize ps = PageSize.A4.rotate();
//        设置pageSize  比率2.833333333 毫米比
        PageSize ps = new PageSize(595F, 395.8167F);
        PdfPage pdfPage = pdfDocument.addNewPage(ps);
        PdfCanvas canvas = new PdfCanvas(pdfPage);
//        设置中心为原点
        canvas.concatMatrix(1, 0, 0, 1, ps.getWidth() / 2, ps.getHeight() / 2);
        Color grayColor = new DeviceCmyk(0.f, 0.f, 0.f, 0.875f);
        Color greenColor = new DeviceCmyk(1.f, 0.f, 1.f, 0.176f);
        Color blueColor = new DeviceCmyk(1.f, 0.156f, 0.f, 0.118f);
        Color titleColor = new DeviceRgb(130, 89, 37);
//        设置粗线
        canvas.setStrokeColor(titleColor).setLineWidth(2);
//        外框绘制
        canvas.moveTo(-ps.getWidth() / 2 + 25, ps.getHeight() / 2 - 90)
                .lineTo(ps.getWidth() / 2 - 25, ps.getHeight() / 2 - 90)
                .lineTo(ps.getWidth() / 2 - 25, -ps.getHeight() / 2 + 35)
                .lineTo(-ps.getWidth() / 2 + 25, -ps.getHeight() / 2 + 35)
                .lineTo(-ps.getWidth() / 2 + 25, ps.getHeight() / 2 - 90).stroke();
//        标题横线绘制
        canvas.moveTo(-ps.getWidth() / 2 + 150, ps.getHeight() / 2 - 58)
                .lineTo(ps.getWidth() / 2 - 150, ps.getHeight() / 2 - 58).stroke();
//        设置细线
        canvas.setStrokeColor(titleColor).setLineWidth(1);
//        绘制横向线框
        canvas.moveTo(-ps.getWidth() / 2 + 150, ps.getHeight() / 2 - 62)
                .lineTo(ps.getWidth() / 2 - 150, ps.getHeight() / 2 - 62).stroke();
        canvas.moveTo(-ps.getWidth() / 2 + 25, ps.getHeight() / 2 - 150)
                .lineTo(ps.getWidth() / 2 - 25, ps.getHeight() / 2 - 150).stroke();
        canvas.moveTo(ps.getWidth() / 2 - 25, -ps.getHeight() / 2 + 115)
                .lineTo(-ps.getWidth() / 2 + 25, -ps.getHeight() / 2 + 115).stroke();
        canvas.moveTo(ps.getWidth() / 2 - 25, -ps.getHeight() / 2 + 95)
                .lineTo(-ps.getWidth() / 2 + 25, -ps.getHeight() / 2 + 95).stroke();
//        x轴坐标数组，绘制上下小横格竖线
        Integer[] smallCol = {-248, 55, 75};
//          上面小格子纵向线框
        for (Integer i : smallCol) {
            canvas.moveTo(i, ps.getHeight() / 2 - 90)
                    .lineTo(i, ps.getHeight() / 2 - 150).stroke();
        }
        //          下面小格子纵向线框
        for (Integer i : smallCol) {
            canvas.moveTo(i, -ps.getHeight() / 2 + 95)
                    .lineTo(i, -ps.getHeight() / 2 + 35).stroke();
        }
//        第一条竖线
        canvas.moveTo(-ps.getWidth() / 2 + 160, ps.getHeight() / 2 - 150)
                .lineTo(-ps.getWidth() / 2 + 160, -ps.getHeight() / 2 + 95).stroke();
//        x轴坐标数组，绘制中间横格竖线
        Integer[] bigCol = {-68, -28, 35, 100, 170, 200};
//        中间大格子后面竖线
        for (Integer i : bigCol) {
            canvas.moveTo(i, ps.getHeight() / 2 - 150)
                    .lineTo(i, -ps.getHeight() / 2 + 115).stroke();
        }
//        设置表格模板字体及字体颜色
        PdfFont txtFont = PdfFontFactory.createFont(File_Path + "simfang.ttf", PdfEncodings.IDENTITY_H, true);
//        设置标题并添加
        Paragraph title = new Paragraph("智为科技普通电子发票")
                .setFont(txtFont).setFontColor(titleColor)
                .setFontSize(26)
                .setFixedPosition(-ps.getWidth() / 2 + 170, ps.getHeight() / 2 - 58, 1000);
        Document document = new Document(pdfDocument);
        //设置税章图片
        Image image = new Image(ImageDataFactory.create(File_Path + "seal.png"));
        image.setFixedPosition(-ps.getWidth() / 2 + 250, ps.getHeight() / 2 - 100)
                .setMaxHeight(70);
        //TODO:
        //设置销售方印章
        Image saleImage = new Image(ImageDataFactory.create(File_Path + "zhiweiSeal.png"));
        saleImage.setFixedPosition(160f, -190f)
                .setMaxHeight(80);
        //添加税章与标题
        document.add(image).add(title).add(saleImage);

        //获取各个标题名称
        ArrayList<txtName> txtList = getTitleList();

        //写入标题
        for (txtName txtName : txtList) {
            addText(document, txtName);
        }

        //获取发票内容
        ArrayList<txtName> list = getTxtList(order, bill, product,
                trader, ourCompany, sealer, dealer);

        //写入标题后面内容信息
        for (txtName txtName : list) {
            addInnerTxt(document, txtName);
        }

//        String url = "01,10,044031600111,25001580,183.82,20161017,05197160245138663193\n";6421626778734121
        String url = String.format("01,10,%s,%s,%s,%s,%s",
                bill.getBillNum(), bill.getInvoicNum(), PriceFormat.format(bill.getTotalPrice()),
                new SimpleDateFormat("yyyyMMdd").format(bill.getCreated()), bill.getVerifyNum());
        Image qrImg = getQrImg(url);
        document.add(qrImg);
        pdfDocument.close();
        return new File(File_Path + "tip.pdf");
    }

    //    在document上写入标题的方法
    public static void addText(Document document, txtName txtName) throws IOException {
        Paragraph paragraph = new Paragraph(txtName.getStr())
                .setFont(PdfFontFactory.createFont(File_Path + "simfang.ttf", PdfEncodings.IDENTITY_H, true))
                .setFontColor(new DeviceRgb(130, 89, 37))
                .setFontSize(12)
                .setFixedPosition(txtName.getX(), txtName.getY(), 1000);
        document.add(paragraph);
    }

    //    在document上写入内容的方法
    public static void addInnerTxt(Document document, txtName txtName) throws IOException {
        Paragraph paragraph = new Paragraph(txtName.getStr())
                .setFont(PdfFontFactory.createFont(File_Path + "simsun.ttf", PdfEncodings.IDENTITY_H, true))
                .setFontColor(new DeviceRgb(0, 0, 0))
                .setFontSize(10)
                .setFixedPosition(txtName.getX(), txtName.getY(), 1000);
        document.add(paragraph);
    }

    //    获取二维码的方法
    public static Image getQrImg(String url) throws IOException {
        BarcodeQRCode qrCode = new BarcodeQRCode(url);
        java.awt.Image awtImage = qrCode.createAwtImage(java.awt.Color.black, java.awt.Color.WHITE);
        BufferedImage bufferedImage = new BufferedImage(128, 128, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = bufferedImage.createGraphics();
        graphics.drawImage(awtImage, 0, 0, 128, 128, java.awt.Color.white, null);
        graphics.dispose();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageIO.write(bufferedImage, "png", outputStream);
        Image QRimg = new Image(ImageDataFactory.create(outputStream.toByteArray()));
        QRimg.setFixedPosition(-267f, 117f)
                .setMaxHeight(72);
        return QRimg;
    }

    //获取发票信息的方法
    private static ArrayList<txtName> getTxtList(Order order, Bill bill, Products product,
                                                 Trader trader, Trader ourCompany, User sealer,
                                                 User dealer) {
        ArrayList<txtName> list = new ArrayList<>();
        Trader PartyBuy;
        Trader PartySell;
        //判断交易类型,设置甲乙方
        if (order.getType().equals("入库")) {
            PartyBuy = ourCompany;
            PartySell = trader;
        } else {
            PartyBuy = trader;
            PartySell = ourCompany;
        }
        //表头信息
        list.add(txtName.set(bill.getBillNum(), 212.3f, 160f));//发票代码
        list.add(txtName.set(bill.getInvoicNum(), 212.3f, 144f));//发票号码
        List<String> verifyNumStrList = StrUtil.getStrList(bill.getVerifyNum(), 16);
        for (int i = 0; i < verifyNumStrList.size(); i++) {
            String s = verifyNumStrList.get(i);
            list.add(txtName.set(s, 204f, -(i * 8) + 115f));
        }//效验码
        list.add(txtName.set(new SimpleDateFormat("yyyyMMdd")
                .format(bill.getCreated()), 212.3f, 128f));//开票日期
        //购买方信息
        list.add(txtName.set(PartyBuy.getName(), -207f, 89f));//名称
        list.add(txtName.set(PartyBuy.getTaxNum(), -157.6f, 74.2f));//纳税人识别号
        list.add(txtName.set(PartyBuy.getTelephone(), -169.2f, 61.1f));//电话 开户行及账号
        list.add(txtName.set(PartyBuy.getBankName() + "银行："
                + PartyBuy.getAccountNumber(), -160f, 47.3f));//电话 开户行及账号
        //密码
        List<String> strList = StrUtil.getStrList(bill.getPassWord(), 36);
        for (int i = 0; i < strList.size(); i++) {
            String s = strList.get(i);
            list.add(txtName.set(s, 79.23f, -(i * 14) + 93.46f));
        }
        //销售方信息
        list.add(txtName.set(PartySell.getName(), -207f, -118f));//名称
        list.add(txtName.set(PartySell.getTaxNum(), -159.23f, -132f));//纳税人识别号
        list.add(txtName.set(PartySell.getTelephone(), -168.46f, -146f));//电话 开户行及账号
        list.add(txtName.set(PartySell.getBankName() + "银行："
                + PartySell.getAccountNumber(), -158.46f, -160f));//电话 开户行及账号
        //添加中间区域主内容
        List<String> productNameStrList = StrUtil.getStrList(product.getName(), 10);
        for (int i = 0; i < productNameStrList.size(); i++) {
            String s = productNameStrList.get(i);
            list.add(txtName.set(s, -254.6f, -(i * 14) + 12.69f));
        }//货物名
        List<String> modelStrList = StrUtil.getStrList(product.getModel(), 11);
        for (int i = 0; i < modelStrList.size(); i++) {
            String s = modelStrList.get(i);
            list.add(txtName.set(s, -130f, -(i * 14) + 12.69f));
        }//型号
        list.add(txtName.set(product.getUnit(), -56.92f, 12.69f));//单位
        list.add(txtName.set(String.valueOf(order.getNumber()), -12f, 12.69f));//数量
        list.add(txtName.set(PriceFormat.format(product.getUnitPrice()) + "元", 42.30f, 12.69f));//单价
        list.add(txtName.set("￥" + PriceFormat.format(new BigDecimal(product.getUnitPrice()).multiply(new BigDecimal(order.getNumber()))), 103f, 12.69f));//金额
        list.add(txtName.set(String.valueOf(PartySell.getTaxRate()), 174f, 12.69f));//税率
        String taxMoney = PriceFormat.format(new BigDecimal(product.getUnitPrice())
                .multiply(new BigDecimal(order.getNumber()))
                .multiply(new BigDecimal(PartySell.getTaxRate())
                        .divide(new BigDecimal(10)))) + "元";
        list.add(txtName.set(taxMoney, 208f, 12.69f));//税额
        //大写
        double value = new BigDecimal(product.getUnitPrice()).multiply(new BigDecimal(order.getNumber())).doubleValue();
        String money = Money.Turn(value);
        list.add(txtName.set(money, -126.92f, -100f));
        //小写
        list.add(txtName.set(PriceFormat.format(value) + "元", 156f, -100f));
        //备注
        list.add(txtName.set(bill.getRemark(), 83f, -119.6f));
        //下方表审批
        list.add(txtName.set(PartySell.getContacts(), -204.6f, -184f));//收款人
        list.add(txtName.set(dealer.getUsername(), -100f, -184f));//复核
        list.add(txtName.set(sealer.getUsername(), 30f, -184f));//开票人
        return list;
    }

    //获取标题的方法
    private static ArrayList<txtName> getTitleList() {
        ArrayList<txtName> txtList = new ArrayList<>();
        txtList.add(txtName.set("发票代码：", 160f, 160f));
        txtList.add(txtName.set("发票号码：", 160f, txtList.get(0).getY() - 16));
        txtList.add(txtName.set("开票日期：", 160f, txtList.get(1).getY() - 16));
        txtList.add(txtName.set("校验码：", 160f, txtList.get(2).getY() - 16));
        txtList.add(txtName.set("名称：", -245f, 88f));
        txtList.add(txtName.set("纳税人识别号：", txtList.get(4).getX(), txtList.get(4).getY() - 14));
        txtList.add(txtName.set("地址、电话：", txtList.get(4).getX(), txtList.get(5).getY() - 14));
        txtList.add(txtName.set("开户行及账号：", txtList.get(4).getX(), txtList.get(6).getY() - 14));
        txtList.add(txtName.set("货物或劳务、服务名称", -265f, 30f));
        txtList.add(txtName.set("规格型号", -125f, txtList.get(8).getY()));
        txtList.add(txtName.set("单位", -60f, txtList.get(8).getY()));
        txtList.add(txtName.set("数量", -10f, txtList.get(8).getY()));
        txtList.add(txtName.set("单价", 55f, txtList.get(8).getY()));
        txtList.add(txtName.set("金额", 125f, txtList.get(8).getY()));
        txtList.add(txtName.set("税率", 174f, txtList.get(8).getY()));
        txtList.add(txtName.set("税额", 225f, txtList.get(8).getY()));
        txtList.add(txtName.set("合    计", -230f, -83f));
        txtList.add(txtName.set("价格合计（大写）", -250f, -103f));
        txtList.add(txtName.set("（小写）", 110f, -103f));
        txtList.add(txtName.set("名称：", -245f, -120f));
        txtList.add(txtName.set("纳税人识别号：", txtList.get(19).getX(), txtList.get(19).getY() - 14));
        txtList.add(txtName.set("地址、电话：", txtList.get(19).getX(), txtList.get(20).getY() - 14));
        txtList.add(txtName.set("开户行及账号：", txtList.get(19).getX(), txtList.get(21).getY() - 14));
        txtList.add(txtName.set("收款人：", -255f, -185f));
        txtList.add(txtName.set("复核：", txtList.get(23).getX() + 120f, txtList.get(23).getY()));
        txtList.add(txtName.set("开票人：", txtList.get(24).getX() + 120f, txtList.get(23).getY()));
        txtList.add(txtName.set("销售方：（章）", txtList.get(25).getX() + 120f, txtList.get(23).getY()));
        txtList.add(txtName.set("购", -266f, 85f));
        txtList.add(txtName.set("买", txtList.get(27).getX(), txtList.get(27).getY() - 16));
        txtList.add(txtName.set("方", txtList.get(27).getX(), txtList.get(28).getY() - 16));
        txtList.add(txtName.set("销", txtList.get(27).getX(), -125f));
        txtList.add(txtName.set("售", txtList.get(27).getX(), txtList.get(30).getY() - 16));
        txtList.add(txtName.set("方", txtList.get(27).getX(), txtList.get(31).getY() - 16));
        txtList.add(txtName.set("密", 58f, 85f));
        txtList.add(txtName.set("码", txtList.get(33).getX(), txtList.get(33).getY() - 16));
        txtList.add(txtName.set("区", txtList.get(33).getX(), txtList.get(34).getY() - 16));
        txtList.add(txtName.set("备", txtList.get(33).getX(), -125f));
        txtList.add(txtName.set("注", txtList.get(33).getX(), txtList.get(36).getY() - 32));
        return txtList;
    }
}

@Data
@Accessors(chain = true)
class txtName {
    private String str;
    private Float x;
    private Float y;

    public static txtName set(String str, Float x, Float y) {
        return new txtName().setStr(str).setX(x).setY(y);
    }
}

//double类型转换为中文大写
class Money {
    static String moneyD = new String();
    static String moneyBefore = new String();
    static String moneyAfter = new String();
    static StringBuffer moneyA = new StringBuffer();

    public static String getTurns(int i) {
        switch (i) {
            case 2:
                moneyD = "拾";
                break;
            case 3:
                moneyD = "佰";
                break;
            case 4:
                moneyD = "仟";
                break;
            case 5:
                moneyD = "万";
                break;
            case 6:
                moneyD = "拾";
                break;
            case 7:
                moneyD = "佰";
                break;
            case 8:
                moneyD = "仟";
                break;
            case 9:
                moneyD = "亿";
                break;
            case 10:
                moneyD = "拾";
                break;
            case 11:
                moneyD = "佰";
                break;
            case 12:
                moneyD = "仟";
                break;
        }
        return moneyD.toString();
    }

    public static String getTurnMoneyWord(String s) {
        switch (Integer.parseInt(s)) {
            case 0:
                return "零";
            case 1:
                return "壹";
            case 2:
                return "贰";
            case 3:
                return "叁";
            case 4:
                return "肆";
            case 5:
                return "伍";
            case 6:
                return "陆";
            case 7:
                return "柒";
            case 8:
                return "捌";
        }
        return "玖";
    }

    public static String getTurnMoneys(String money) {
        //清除stringBuffer的内容
        int sb_length = moneyA.length();
        moneyA.delete(0, sb_length);
        try {
            if (money.indexOf("-") != -1) {
                moneyA.append("负");
                money = money.substring(money.indexOf("-") + 1, money.length());
            }
            if (money.indexOf(".") != -1) {
                moneyBefore = money.substring(0, money.indexOf("."));
                moneyAfter = money.substring(money.indexOf(".") + 1, money.length());
            } else {
                moneyBefore = money;
                moneyAfter = "none";
            }
            if (moneyBefore.length() == 1 && moneyBefore.charAt(0) == '0' && moneyAfter == "none") {
                moneyA.append("零");
                moneyA.append("圆");
            } else {
                for (int i = 0; i < moneyBefore.length(); i++) {
                    if (moneyBefore.charAt(i) != '0') {
                        moneyA.append(getTurnMoneyWord(
                                String.valueOf(
                                        String.valueOf(moneyBefore.charAt(i))).concat("")));
                        if (moneyBefore.length() != i + 1)
                            moneyA.append(getTurns(moneyBefore.length() - i));
                        continue;
                    }
                    if (moneyBefore.length() - i == 5 && (moneyBefore.length() > 5 && moneyBefore.length() <= 9))
                        moneyA.append("万");
                    if (moneyBefore.length() - i == 9 && moneyBefore.length() > 9)
                        moneyA.append("亿");
                    if (moneyBefore.length() != i + 1 && moneyBefore.charAt(i + 1) != '0')
                        moneyA.append("零");
                }
                if (moneyBefore.length() != 1 || moneyBefore.charAt(0) != '0') {
                    moneyA.append("圆");
                }
            }
            if (!moneyAfter.equals("none")) {
                for (int i = 0; i < moneyAfter.length(); i++) {
                    if (i == 0)
                        if (moneyAfter.charAt(i) != '0') {
                            moneyA.append(getTurnMoneyWord(String.valueOf(String.valueOf(
                                    moneyAfter.charAt(i))).concat("")));
                            moneyA.append("角");
                        } else if (moneyBefore.charAt(0) != '0' && moneyAfter.length() > 1 && (!moneyAfter.equals("00")))
                            moneyA.append("零");
                    if (i == 1 && moneyAfter.charAt(i) != '0') {
                        moneyA.append(getTurnMoneyWord(String.valueOf(
                                String.valueOf(moneyAfter.charAt(i))).concat(
                                "")));
                        moneyA.append("分");
                    }
                }

            }
            if (moneyAfter.equals("none") || moneyAfter.length() != 2 || moneyAfter.equals("00"))
                moneyA.append("整");
        } catch (Exception exception) {
        }
        return moneyA.toString();
    }

    public static String Turn(Double money) {
        String format = TipGener.PriceFormat.format(money);
        return getTurnMoneys(format);
    }

}